#include<iostream>
#include<pthread.h>
#include<functional>
#include<queue>
#include<vector>
#include<time.h>
#include<unistd.h>
#include<string>
#include<stdarg.h>

using namespace std;

//用于日志功能中对显示器加锁保护
pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER;

//日志功能
//日志等级
enum LogLevel
{
    DEBUG=0,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

//将日志等级转化为字符串
string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
        return "Debug";
    case INFO:
        return "Info";
    case WARNING:
        return "Warning";
    case ERROR:
        return "Error";
    case FATAL:
        return "Fatal";
    default:
        return "Unknown";
    }
}

//获取特定的时间格式
string GetTimeString()
{
    time_t curr_time = time(nullptr);
    struct tm *format_time = localtime(&curr_time);
    if (format_time == nullptr)
        return "None";
    char time_buffer[1024];
    snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",
             format_time->tm_year + 1900,
             format_time->tm_mon + 1,
             format_time->tm_mday,
             format_time->tm_hour,
             format_time->tm_min,
             format_time->tm_sec);
    return time_buffer;
}


void LogMsg(string filename,int line,int level,const char* format,...)
{
    std::string levelstr = LevelToString(level);
    std::string timestr = GetTimeString();
    pid_t selfid = getpid();
    char buffer[1024];
    va_list arg;
    va_start(arg, format);
    vsnprintf(buffer, sizeof(buffer), format, arg);
    va_end(arg);

    std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +
                          "[" + std::to_string(selfid) + "]" +
                          "[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer + "\n";
    pthread_mutex_lock(&log_lock);
    cout << message;
    pthread_mutex_unlock(&log_lock);
}

//宏定义
#define LOG(level, format, ...)                                 \       
do                                                              \
{                                                               \
    LogMsg(__FILE__, __LINE__, level, format, ##__VA_ARGS__);   \
}                                                               \
while(0)

//线程封装
class Pthread
{
public:
    Pthread(function<void()> func,string name)
        :_func(func)
        ,_pthread_name(name)
    {}

    ~Pthread()
    {}

    static void* thread_func(void* arg)

    {
        Pthread* p=reinterpret_cast<Pthread*>(arg);
        p->_func();
        return nullptr;
    }

    void Start()
    {
        if(-1==pthread_create(&_pthread_id,NULL,thread_func,this))
        {
            perror("pthread_create");
            return;
        }
    }

    void Wait()
    {
        pthread_join(_pthread_id,NULL);
    }

    void Detach()
    {
        pthread_detach(_pthread_id);
    }

    string GetPthreadName()
    {
        return _pthread_name;
    }
  
private:
    pthread_t _pthread_id;//线程ID
    string _pthread_name;//线程名
    function<void()> _func;//线程执行的函数
};

template<class T>
class ThreadPool
{
public:
    ThreadPool(size_t threads_num=3)
        :_threads_num(threads_num)
        ,_wait_num(0)
    {
        LOG(DEBUG,"thread pool init");
        _tp.reserve(threads_num);
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
    }

    ~ThreadPool()
    {
        LOG(DEBUG,"thread pool destroy");
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
    }

    void Thread_func()
    {
        LOG(DEBUG,"thread execute");
        while(true)
        {
            pthread_mutex_lock(&_mutex);
            while(_task.empty())
            {
                ++_wait_num;
                pthread_cond_wait(&_cond,&_mutex);
                --_wait_num;
            }
            LOG(DEBUG,"thread get task");
            T t=_task.front();
            _task.pop();
            pthread_mutex_unlock(&_mutex);
            LOG(DEBUG,"thread starts to execute task");
            t();
            LOG(DEBUG,"thread completed task");
        }
    }

    void Start()
    {
        LOG(DEBUG,"threads Start");
        int i=0;
        for(i=0;i<_threads_num;++i)
        {
            _tp.emplace_back(Pthread(bind(&ThreadPool::Thread_func,this),"Thread"+to_string(i)));
            _tp.back().Start();
        }
    }

    void PushTask(T t)
    {
        LOG(DEBUG,"PushTask");
        pthread_mutex_lock(&_mutex);
        _task.push(t);
        pthread_cond_signal(&_cond);
        pthread_mutex_unlock(&_mutex);
    }

    void Wait()
    {                            
        LOG(DEBUG,"thread wait");
        for(auto& e:_tp)
        {
            e.Wait();
        }
        LOG(DEBUG,"thread end wait");
    }

private:
    queue<T> _task;//任务队列
    vector<Pthread> _tp;//线程池
    pthread_mutex_t _mutex;//用于对任务队列加锁保护
    pthread_cond_t _cond;//线程在该条件变量下面等待任务分配
    size_t _threads_num;//线程池中线程个数
    size_t _wait_num;//休眠中的线程个数
};

void Task()
{
    int a=rand()%100;
    int b=rand()%100;
    int sum=a+b;
    string ret=to_string(a)+" + "+to_string(b)+" = "+to_string(sum);
    cout<<ret<<endl;
}

int main()
{
    srand(time(nullptr));
    auto tp=ThreadPool<function<void()>>(5);
    tp.Start();
    int count=10;
    while(count--)
    {
        tp.PushTask(Task);
        sleep(1);
    }
    tp.Wait();
    return 0;
}